fix(metadata-protocol): deleteMany/updateMany 的 atomic 要么为真、要么拒绝 (#4620) - #4798
Merged
Conversation
ADR-0119 D4 把 `batchData` 的 `atomic` 修成了真承诺,同一文件里的两个同胞 当时不在那次 PR 的确认范围内,缺陷原样留着: - `deleteManyData` 是假原子:`if (options?.atomic) break;` 没开任何事务, 失败前已删掉的行保持已删除,响应却以原子自居并把它们报成 success。比 `batchData` 那次更糟 —— 部分删除没有自然的撤销手段。 - `updateManyData` 根本不读 `atomic`:选项被接受、被声明成全有或全无,却从 未被读取,调用方拿到的是无任何信号的 best-effort。 两者现在走与 `batchData` 完全相同的原子臂 —— 抽成一个共享 runner (`runAtomicBatch`),而不是把事务处理再抄两份(抄写正是下一个同胞漂移回 谎言的路径): - `atomic: true` 时整批跑在一个 `engine.transaction()` 里,首个失败回滚此前 全部写入; - 回滚批次报告零成功,行分别标记 `ROLLED_BACK:` / `NOT_ATTEMPTED:`,致因行 保留原始错误,客户端可区分「已尝试但被撤销」与「从未执行」; - `atomic` 优先于 `continueOnError`; - 无法回滚的运行时(无 `engine.transaction()`,或默认 driver 无 `beginTransaction`)对 `atomic: true` 返回 501 NOT_IMPLEMENTED,而不是静默 降级成 best-effort —— 静默降级正是本 issue 的缺陷类别。 非原子路径(含 `continueOnError` 交互与响应形状)保持不变;`batchData` 的 既有测试未作任何改动仍全部通过。 逐行结果形状与 `BatchOperationResultSchema` 的分歧(issue 第 3 节)刻意未动: 那是公开 wire 契约决定,单独跟踪。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018iARDqtrhQgz6fVHDeDkbQ
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 3 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
) 同一个包、同一类变更、同一种调用方可见后果:`atomic: true` 在不能回滚的运行时上 从「200 部分成功」变成 501。D4 给 `batchData` 定的就是 minor (`.changeset/adr-0119-plugin-reachable-transactions.md`),这次给 `deleteManyData` / `updateManyData` 做同一件事不能是 patch —— 包当前是 17.0.0-rc.1,patch 会发成 17.0.1,等于告诉消费者什么都没变。 只改 bump 一行,正文不动。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018iARDqtrhQgz6fVHDeDkbQ
xuyushun441-sys
marked this pull request as ready for review
August 3, 2026 07:34
This was referenced Aug 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4620
ADR-0119 D4 把
batchData的atomic修成了真承诺。同一文件里的两个同胞当时不在那次 PR 的确认范围内,缺陷原样留着 —— 本 PR 只做 issue 的第 1、2 节。修了什么
1.
deleteManyData的假原子(protocol.ts)if (options?.atomic) break;只是跳出循环:没有事务、没有回滚。失败前已删掉的行保持已删除,而响应以原子自居并把它们报成success: true。这比batchData那次更糟 —— 部分删除没有自然的撤销手段,客户端无法从自己的请求里把行重建回来。2.
updateManyData完全不读atomic选项被接受、在
BatchOptionsSchema里被声明成「全有或全无」,却从未被读取。调用方要原子性,拿到的是 best-effort,且没有任何信号 —— 典型的 declared ≠ enforced,而且是写路径上的保证。怎么修的:复用,不重新推导
D4 的三块料(原子臂、共享逐记录循环、fail-closed 能力闸门、
ROLLED_BACK:/NOT_ATTEMPTED:行标记)都已在main上,本 PR 一律复用。为避免出现第三、第四份事务处理代码(抄写正是下一个同胞漂移回谎言的路径),把batchData原子臂里除「逐记录循环 + 两个响应构造器」以外的部分抽成一个共享 runnerrunAtomicBatch,三个入口共用:atomic: true→ 整批跑在一个engine.transaction()里,首个失败回滚此前全部写入;ROLLED_BACK: record < i > failed — < cause >,没轮到的行标NOT_ATTEMPTED: atomic batch aborted by record < i >,致因行保留自己的原始错误 —— 客户端能区分「已尝试但被撤销」与「从未执行」;atomic优先于continueOnError(后者的契约文本本来就把自己限定在atomic=false);engine.transaction(),或默认 driver 无beginTransaction)→ 501NOT_IMPLEMENTED,而不是静默降级成 best-effort。静默降级正是本 issue 的缺陷类别,所以这里 fail closed。batchData的行为一点没动,其既有测试文件未作任何修改仍全部通过。行为变更(需要知会使用者)
atomic: true的deleteMany/updateMany在不能回滚的运行时上从「静默 best-effort」变成 501 拒绝。想要 best-effort 就明确要 ——atomic: false或不传。changeset 里写了这条。非原子路径(含
continueOnError交互与两个端点的响应形状)保持不变,并加了回归钉。测试
新增
packages/metadata-protocol/src/protocol.many-data-atomic.test.ts(14 例,均引用 #4620)。假引擎是一个带快照/恢复事务语义的内存 store,所以回滚是真回滚:deleteMany原子 + 中途失败:回滚后a、c两行仍可读(这是本 issue 的关键 —— 部分删除没有自然撤销),零成功,行标ROLLED_BACK:/NOT_ATTEMPTED:;updateMany原子 + 中途失败:先前的更新被恢复成旧值,同样零成功、同样标记;continueOnError交互不变。protocol.delete-many.test.ts里原先钉住假原子的那一例(atomic aborts the remaining ids on the first failure,断言succeeded: 1)改成钉拒绝语义 —— 它钉的正是本次要修掉的行为。刻意没做
issue 第 3 节(逐行结果形状
{ id, success, error, record }与BatchOperationResultSchema的{ errors, data }分歧)未触碰。那是公开 wire 契约的方向决定,两个方向对已发布客户端的影响相反;ADR-0119 D4 当时刻意没让它搭在 bug fix 上,让它搭在这次修复上会是同一种静默兼容性破坏。已由单独的决策 issue 承接。🤖 Generated with Claude Code
https://claude.ai/code/session_018iARDqtrhQgz6fVHDeDkbQ
Generated by Claude Code